package com.apetrenko.avaya.callstore.server;

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import org.xiph.speex.AudioFileWriter;
import org.xiph.speex.OggSpeexWriter;
import org.xiph.speex.SpeexEncoder;

import com.apetrenko.avaya.callstore.client.Config;

public class Archiver {

	private static final Object VRL_FILE_SIGN = "Avaya";
	private File iVrlDir;
	private File iArchiveDir;
	private DbAdapter iDbAdapter;

	public void processAll() {
		if ((iVrlDir == null) || (iArchiveDir == null)) {
			return;
		}
		File[] vFiles = iVrlDir.listFiles();
		File vFile = null;
		for (int i = 0; i < vFiles.length; i++) {
			vFile = vFiles[i];
			archiveFile(vFile);
		}
	}

	private void archiveFile(File aFile) {
		RecordInfo vInfo = getRecordInfo(aFile);

		if (vInfo == null) {
			return;
		}
		String vDestName = getDestFileName(vInfo);
		vInfo.setArchiveFileName(vDestName);
		storeRecordInfo(vInfo);
		try {
			copyToArchive(aFile, vDestName);
			aFile.delete();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private void copyToArchive(File aFile, String aDestName) throws Exception {
		File vFile = new File(aDestName);
		vFile.getParentFile().mkdirs();
		
		SpeexEncoder speexEncoder = new SpeexEncoder();
		int mode = 1;
		int quality = 5;
		int sampleRate = 8000;
		int channels = 1;
		int complexity = 3;
		boolean vbr = true;
		int vbr_quality = 0;
		boolean vad = true;
		boolean dtx = true;
		int nframes = 1;
		byte[] temp = new byte[2560];

		DataInputStream dis = new DataInputStream(new FileInputStream(aFile));

		speexEncoder.init(mode, quality, sampleRate, channels);
		if (complexity > 0) {
			speexEncoder.getEncoder().setComplexity(complexity);
		}

		if (vbr) {
			speexEncoder.getEncoder().setVbr(vbr);

			if (vbr_quality > 0) {
				speexEncoder.getEncoder().setVbrQuality(vbr_quality);
			}
		}

		if (vad) {
			speexEncoder.getEncoder().setVad(vad);
		}

		if (dtx) {
			speexEncoder.getEncoder().setDtx(dtx);
		}

		// Open the file writer
		AudioFileWriter writer;
		writer = new OggSpeexWriter(mode, sampleRate, channels, nframes, vbr);

		writer.open(aDestName);
		writer.writeHeader("Encoded with: JSpeex");
		int pcmPacketSize = 2 * channels * speexEncoder.getFrameSize();
		try {
			// read until we get to EOF
			while (true) {
				dis.readFully(temp, 0, nframes * pcmPacketSize);
				for (int i = 0; i < nframes; i++)
					speexEncoder.processData(temp, i * pcmPacketSize,
							pcmPacketSize);
				int encsize = speexEncoder.getProcessedData(temp, 0);
				if (encsize > 0) {
					writer.writePacket(temp, 0, encsize);
				}
			}
		} catch (EOFException e) {
		}
		writer.close();
		dis.close();
	}

	private void storeRecordInfo(RecordInfo aInfo) {
		iDbAdapter.storeRecordInfo(aInfo);

	}

	private String getDestFileName(RecordInfo aInfo) {
		String vResult = "";
		String vSep = File.separator;
		String vRoot = iArchiveDir.getAbsolutePath();

		DateFormat vFormat = new SimpleDateFormat("yyyy-MM-dd");
		DateFormat vTimeFormat = new SimpleDateFormat("HH-mm-ss");
		String vDateDir = vFormat.format(aInfo.getStartTime());
		String vOpDir = aInfo.getOperator();

		String vFileName = vTimeFormat.format(aInfo.getStartTime()) + "_"
				+ aInfo.getOriginator() + ".spx";

		vResult = vRoot + vSep + vDateDir + vSep + vOpDir + vSep + vFileName;

		return vResult;
	}

	private RecordInfo getRecordInfo(File aFile) {

		RecordInfo vResult = new RecordInfo();
		byte[] vBytes = new byte[11];
		FileInputStream vStream = null;

		vResult.setOriginalFileName(aFile.getName());

		try {
			vStream = new FileInputStream(aFile);

			vStream.skip(44);
			vStream.read(vBytes, 0, 5);
			String vSignature = new String(Arrays.copyOfRange(vBytes, 0, 5));

			if (vSignature.equals(VRL_FILE_SIGN)) {

				vStream.skip(27);
				vStream.read(vBytes, 0, 11);
				vResult.setOriginator(new String(vBytes));

				vStream.skip(53);
				vStream.read(vBytes, 0, 4);

				long vTs = getTimestamp(Arrays.copyOfRange(vBytes, 0, 4));

				vResult.setStartTime(new Date(vTs));

				vStream.skip(2);
				vStream.read(vBytes, 0, 11);
				vResult
						.setOperator(new String(Arrays
								.copyOfRange(vBytes, 0, 4)));
			} else {
				vResult = null;
			}

		} catch (Exception vE) {
			vResult = null;
		} finally {
			if (vStream != null) {
				try {
					vStream.close();
				} catch (IOException e) {
				}
			}
			vBytes = null;
		}
		return vResult;
	}

	private long getTimestamp(byte[] aBytes) {
		long vMagicNumber = -2177452800l;

		String vStrVal = "";
		int vVal = 0;
		for (int i = aBytes.length - 1; i >= 0; i--) {
			byte vByte = aBytes[i];
			vVal = (vByte >= 0) ? vByte : 256 + vByte;
			if (vVal > 0xF) {
				vStrVal = vStrVal + Integer.toHexString(vVal);
			} else {
				vStrVal = vStrVal + "0" + Integer.toHexString(vVal);
			}
		}
		return ((Long.parseLong(vStrVal, 16) + vMagicNumber) * 1000);
	}

	// private void copyToArchive(File aSrcFile, String aDestLocation) {
	// File vDest = new File(aDestLocation);
	// File vDir = vDest.getParentFile();
	// try {
	// vDir.mkdirs();
	// FileChannel in = (new FileInputStream(aSrcFile)).getChannel();
	// FileChannel out = (new FileOutputStream(vDest)).getChannel();
	// in.transferTo(0, aSrcFile.length(), out);
	// in.close();
	// out.close();
	// } catch (Exception e) {
	// e.printStackTrace();
	// }
	// }

	public void init(Config aConfig) {
		setVrlPath(aConfig.getVrlPath());
		setArchivePath(aConfig.getArchivePath());
	}

	private void setArchivePath(String aArchivePath) {
		iArchiveDir = new File(aArchivePath);
		if (!iArchiveDir.exists()) {
			iArchiveDir.mkdirs();
		}
		if (!iArchiveDir.canWrite()) {
			iArchiveDir = null;
		}
	}

	private void setVrlPath(String aVrlPath) {
		iVrlDir = new File(aVrlPath);
		if (!iVrlDir.exists() || !iVrlDir.isDirectory()) {
			iVrlDir = null;
		}

	}

	public void close() {
		// TODO Auto-generated method stub

	}

	public void setDbAdapter(DbAdapter aDbAdapter) {
		iDbAdapter = aDbAdapter;

	}

}
